<template>
    <div class="page">
        <h2 class="title">承运合同管理</h2>

        <!-- 搜索区（提交式） -->
        <div class="search">
            <div class="row">
                <label>合同标题：</label>
                <input v-model="inputFilters.contractTitle" placeholder="请输入合同标题" @keyup.enter="handleSearch"
                    @input="handleSearch" />

                <label>外协单位：</label>
                <input v-model="inputFilters.partnerUnit" placeholder="请输入外协单位" @keyup.enter="handleSearch"
                    @input="handleSearch" />

                <label>经办人：</label>
                <input v-model="inputFilters.handler" placeholder="请输入经办人" @keyup.enter="handleSearch"
                    @input="handleSearch" />
            </div>
            <div class="row">
                <label>签订时间：</label>
                <input type="date" v-model="inputFilters.signingStart" @keyup.enter="handleSearch"
                    @change="handleSearch" />
                <span> - </span>
                <input type="date" v-model="inputFilters.signingEnd" @keyup.enter="handleSearch"
                    @change="handleSearch" />

                <label>审批状态：</label>
                <select v-model="inputFilters.status" @change="handleSearch">
                    <option value="">全部</option>
                    <option value="待提交">待提交</option>
                    <option value="已审核">已审核</option>
                    <option value="已拒绝">已拒绝</option>
                </select>

                <button class="btn primary" @click="handleSearch">查询</button>
                <button class="btn" @click="handleReset">重置</button>
            </div>
        </div>

        <div class="toolbar">
            <button class="btn primary" @click="handleCreate">新增</button>
            <button class="btn danger" :disabled="selectedIds.length === 0" @click="handleBatchDelete">删除</button>
        </div>

        <!-- 表格 -->
        <div class="table-wrapper">
            <table class="table">
                <thead>
                    <tr>
                        <th style="width: 36px"><input type="checkbox" :checked="allSelected" @change="toggleAll" />
                        </th>
                        <th>合同编号</th>
                        <th>合同标题</th>
                        <th>外协单位</th>
                        <th>外协负责人</th>
                        <th>线路</th>
                        <th>吨运价</th>
                        <th>包车条件吨位</th>
                        <th>包车金额</th>
                        <th>签订日期</th>
                        <th>经办人</th>
                        <th>创建时间</th>
                        <th>状态</th>
                        <th>审批人</th>
                        <th>操作</th>
                    </tr>
                </thead>
                <tbody>
                    <tr v-if="loading">
                        <td :colspan="15" style="text-align:center">加载中...</td>
                    </tr>
                    <tr v-else-if="rows.length === 0">
                        <td :colspan="15" style="text-align:center">暂无数据</td>
                    </tr>
                    <tr v-for="row in rows" :key="row.id">
                        <td><input type="checkbox" :checked="selectedIds.includes(row.id)"
                                @change="toggleOne(row.id)" /></td>
                        <td>{{ row.contractNumber || '-' }}</td>
                        <td>{{ row.contractTitle || '-' }}</td>
                        <td>{{ row.partnerUnit || '-' }}</td>
                        <td>{{ row.partnerContact || '-' }}</td>
                        <td>{{ row.route || '-' }}</td>
                        <td>{{ row.tonFreightRate }}</td>
                        <td>{{ row.charterConditionTonnage }}</td>
                        <td>{{ row.charterAmount }}</td>
                        <td>{{ row.signingDate }}</td>
                        <td>{{ row.handler || '-' }}</td>
                        <td>{{ row.createdAt }}</td>
                        <td>{{ row.status || '-' }}</td>
                        <td>{{ row.approver || '-' }}</td>
                        <td>
                            <a href="javascript:void(0)" @click="handleEdit(row)">编辑</a>
                            &nbsp;|&nbsp;
                            <a href="javascript:void(0)" class="danger" @click="handleDelete(row)">删除</a>
                            &nbsp;|&nbsp;
                            <a href="javascript:void(0)" @click="handleView(row)">查看</a>
                            &nbsp;|&nbsp;
                            <a href="javascript:void(0)" @click="handleSubmitApproval?.(row)">提交审批</a>
                        </td>
                    </tr>
                </tbody>
            </table>
        </div>

        <!-- 分页（数字页码 + 跳转） -->
        <div class="pagination advanced" v-if="total > 0">
            <span class="sum">共{{ totalPage }}页/{{ total }}条数据</span>
            <button class="nav" :disabled="page === 1" @click="goto(page - 1)">‹</button>
            <button v-for="p in pagesToShow" :key="p.key" class="num"
                :class="{ active: p.page === page, ellipsis: p.ellipsis }" :disabled="p.ellipsis"
                @click="!p.ellipsis && goto(p.page)">
                {{ p.label }}
            </button>
            <button class="nav" :disabled="page >= totalPage" @click="goto(page + 1)">›</button>
            <span class="jump">跳至</span>
            <input class="jump-input" type="number" min="1" :max="Math.max(totalPage, 1)" v-model.number="jumpPage"
                @keyup.enter="jump()" />
            <span class="jump">页</span>
        </div>

        <!-- 详情弹窗 -->
        <div class="dialog-mask" v-if="showDetail" @click.self="closeDetail">
            <div class="dialog">
                <h3>合同详情</h3>
                <div v-if="detailLoading">加载中...</div>
                <div v-else>
                    <p><b>合同编号：</b>{{ detail.contractNumber || '-' }}</p>
                    <p><b>合同标题：</b>{{ detail.contractTitle || '-' }}</p>
                    <p><b>外协单位：</b>{{ detail.partnerUnit || '-' }}</p>
                    <p><b>外协负责人：</b>{{ detail.partnerContact || '-' }}</p>
                    <p><b>线路：</b>{{ detail.route || '-' }}</p>
                    <p><b>吨运价：</b>{{ detail.tonFreightRate }}</p>
                    <p><b>包车条件吨位：</b>{{ detail.charterConditionTonnage }}</p>
                    <p><b>包车金额：</b>{{ detail.charterAmount }}</p>
                    <p><b>合同金额：</b>{{ detail.contractAmount || '-' }}</p>
                    <p><b>签订日期：</b>{{ detail.signingDate }}</p>
                    <p><b>经办人：</b>{{ detail.handler || '-' }}</p>
                    <p><b>创建时间：</b>{{ detail.createdAt }}</p>
                    <p><b>状态：</b>{{ detail.status || '-' }}</p>
                    <p><b>审批人：</b>{{ detail.approver || '-' }}</p>
                    <p v-if="detail.contractSubjectDescription"><b>合同标的/项目说明：</b><br />{{
                        detail.contractSubjectDescription }}</p>
                    <p v-if="detail.contractTerms"><b>主要条款/变更条款：</b><br />{{ detail.contractTerms }}</p>
                    <p v-if="detail.attachments && detail.attachments.length"><b>附件：</b>
                        <span v-for="(a, i) in detail.attachments" :key="i">
                            <a :href="a" target="_blank">{{ getFileName(a) }}</a><span
                                v-if="i < detail.attachments.length - 1">, </span>
                        </span>
                    </p>
                </div>
                <div class="dialog-footer">
                    <button class="btn" @click="closeDetail">关闭</button>
                </div>
            </div>
        </div>
    </div>
</template>

<script setup lang="ts">
import { ref, reactive, onMounted, computed } from 'vue'
import { useRouter } from 'vue-router'
import { read, write } from '@/assets/Axios/axiosHttple'

const router = useRouter()

// 提交式查询输入与实际查询条件
const inputFilters = reactive({
    contractTitle: '',
    partnerUnit: '',
    handler: '',
    signingStart: '',
    signingEnd: '',
    status: ''
})
const filters = reactive({
    contractTitle: '',
    partnerUnit: '',
    handler: '',
    signingStart: '',
    signingEnd: '',
    status: ''
})

const page = ref(1)
const pageSize = ref(10)
const total = ref(0)
const totalPage = ref(0)
const loading = ref(false)
const rows = ref<any[]>([])
const jumpPage = ref<number | null>(1)

const selectedIds = ref<number[]>([])
const allSelected = ref(false)

function toggleOne(id: number) {
    if (selectedIds.value.includes(id)) {
        selectedIds.value = selectedIds.value.filter(x => x !== id)
    } else {
        selectedIds.value.push(id)
    }
    allSelected.value = rows.value.length > 0 && selectedIds.value.length === rows.value.length
}
function toggleAll(e: Event) {
    const checked = (e.target as HTMLInputElement).checked
    allSelected.value = checked
    selectedIds.value = checked ? rows.value.map(r => r.id) : []
}

function handleCreate() {
    router.push('/AddCarriageContracts')
}

async function handleDelete(row: any) {
    if (!row || !row.id) return
    if (!confirm(`确认删除合同【${row.contractTitle || row.contractNumber || row.id}】吗？`)) return
    try {
        const deletedBy = localStorage.getItem('username') || '张三'
        const id = Number(row.id)
        const candidates = [
            `contractmanagementwrite/api/ContractManagement/DeleteCarriage/carriage/delete/${encodeURIComponent(String(id))}`,
            `contractmanagementwrite/api/ContractManagement/Delete/delete/${encodeURIComponent(String(id))}`,
            `contractmanagementwrite/api/ContractManagement/DeleteCarriage/carriage/delete`,
            `contractmanagementwrite/api/ContractManagement/Delete/delete`
        ]
        let lastErr: any = null
        for (const u of candidates) {
            try {
                const res = u.endsWith('/delete') || u.endsWith('/delete/batch') ? await write.post(u, { id, deletedBy }) : await write.post(u, { deletedBy })
                const d = res?.data ?? {}
                if (res.status === 200 && (Number(d?.code) === 200 || d?.data === true || typeof d?.data === 'number')) {
                    alert('删除成功')
                    rows.value = rows.value.filter(r => r.id !== row.id)
                    selectedIds.value = selectedIds.value.filter(x => x !== row.id)
                    allSelected.value = rows.value.length > 0 && selectedIds.value.length === rows.value.length
                    fetchList()
                    return
                }
                lastErr = { status: res?.status, body: d }
            } catch (e) { lastErr = e }
        }
        alert(lastErr?.body?.message || lastErr?.message || '删除失败')
    } catch (e: any) { alert(e?.message || '网络异常，请重试') }
}

async function handleBatchDelete() {
    if (selectedIds.value.length === 0) return
    if (!confirm(`确认删除选中的 ${selectedIds.value.length} 条承运合同吗？`)) return
    try {
        const deletedBy = localStorage.getItem('username') || '张三'
        const payload = { ids: selectedIds.value, deletedBy }
        const candidates = [
            'contractmanagementwrite/api/ContractManagement/DeleteRangeCarriage/carriage/delete/batch',
            'contractmanagementwrite/api/ContractManagement/DeleteRange/delete/batch'
        ]
        let lastErr: any = null
        for (const u of candidates) {
            try {
                const res = await write.post(u, payload)
                const d = res?.data ?? {}
                if (res.status === 200 && (Number(d?.code) === 200 || d?.data === true || typeof d?.data === 'number')) {
                    alert('批量删除成功')
                    selectedIds.value = []
                    allSelected.value = false
                    page.value = 1
                    fetchList()
                    return
                }
                lastErr = { status: res?.status, body: d }
            } catch (e) { lastErr = e }
        }
        alert(lastErr?.body?.message || lastErr?.message || '批量删除失败')
    } catch (e: any) { alert(e?.message || '网络异常，请重试') }
}

function handleEdit(row: any) {
    router.push(`/UpdateCarriageContracts?id=${encodeURIComponent(row.id)}`)
}

const showDetail = ref(false)
const detailLoading = ref(false)
const detail = ref<any>({})

function closeDetail() { showDetail.value = false }

async function handleView(row: any) {
    showDetail.value = true
    detailLoading.value = true
    try {
        const id = row?.id
        if (!id) { detail.value = { ...row }; return }
        const base = 'contractmanagementread/api/ContractManagementControllers/GetCarriageById/Carriage'
        const tries = [
            `${base}/${encodeURIComponent(String(id))}`,
            `${base}`
        ]
        let got: any = null
        for (const u of tries) {
            try {
                const res = u.endsWith('Carriage') ? await read.get(u, { params: { id } }) : await read.get(u)
                const json: any = res?.data ?? {}
                const code = Number(json?.code ?? json?.Code ?? (res?.status === 200 ? 200 : 500))
                if (code !== 200) continue
                got = json?.data ?? null
                if (got) break
            } catch { }
        }
        const it = got || row || {}

        // 获取外协单位名称
        let partnerUnit = it.PartnerUnit ?? it.CarrierUnit ?? it.UnitName ?? it.unitName ?? it.CompanyName ?? it.companyName ?? it.partnerUnit

        // 如果外协单位信息缺失，尝试通过unitId获取
        if (!partnerUnit && (it.unitId || it.UnitId)) {
            try {
                const unitId = it.unitId || it.UnitId
                const res = await read.get('baseinforead/api/External/GetExternalList', { params: { PageIndex: 1, PageSize: 999 } })
                if (res?.status === 200) {
                    const data = res.data
                    const unitList = Array.isArray(data?.data) ? data.data : (Array.isArray(data?.data?.data) ? data.data.data : [])
                    const unit = unitList.find((u: any) => (u.Id || u.id) == unitId)
                    if (unit) {
                        partnerUnit = unit.UnitName ?? unit.unitName ?? unit.Name ?? unit.name ?? unit.CompanyName ?? unit.companyName
                    }
                }
            } catch (error) {
                // 静默处理错误
            }
        }

        // 详情：直接显示后端返回的线路字段原样（如果是对象则序列化为 JSON 字符串）
        const detailRouteRaw = it.Route ?? it.route ?? it.RouteName ?? it.routeName ?? it.RouteId ?? it.routeId ?? it.RouteInfoId ?? it.routeInfoId ?? ''
        const detailRoute = (detailRouteRaw === null || detailRouteRaw === undefined) ? '' : (typeof detailRouteRaw === 'object' ? JSON.stringify(detailRouteRaw) : String(detailRouteRaw))

        detail.value = {
            id: it.Id ?? it.id,
            contractNumber: it.ContractNumber ?? it.contractNumber,
            contractTitle: it.ContractTitle ?? it.contractTitle,
            partnerUnit: partnerUnit || '',
            partnerContact: it.PartnerContact ?? it.CarrierContact ?? it.carriageRepresentative ?? it.CarriageRepresentative ?? it.ownerName ?? it.OwnerName ?? it.partnerContact ?? '',
            route: detailRoute || '',
            tonFreightRate: it.TonFreightRate ?? it.tonFreightRate ?? '',
            charterConditionTonnage: it.CharterConditionTonnage ?? it.charterConditionTonnage ?? '',
            charterAmount: it.CharterAmount ?? it.charterAmount ?? '',
            signingDate: normalizeDateString(it.SigningDate ?? it.signingDate),
            handler: it.Handler ?? it.handler ?? '',
            createdAt: normalizeDateString(it.CreatedAt ?? it.createdAt),
            status: it.Status ?? it.status ?? '',
            approver: it.Approver ?? it.approver ?? '',
            attachments: Array.isArray(it.contractAttachments) ? it.contractAttachments : (it.contractAttachments ? String(it.contractAttachments).split(',') : (it.fileUrl ? [it.fileUrl] : (it.filePath ? [it.filePath] : [])))
        }
    } finally {
        detailLoading.value = false
    }
}

// 提交审批：本地直接成功并更新状态与审批人
async function handleSubmitApproval(row: any) {
    if (!row) { alert('缺少记录ID，无法提交审批'); return }
    try {
        row.status = '待审核'
        row.approver = '王总'
        const idx = rows.value.findIndex(r => r.id === row.id)
        if (idx >= 0) rows.value[idx] = { ...rows.value[idx], status: row.status, approver: row.approver }
    } finally {
        alert('提交成功')
    }
}

// 防抖定时器
let searchTimeout: number | null = null

function handleSearch() {
    // 清除之前的定时器
    if (searchTimeout) {
        clearTimeout(searchTimeout)
    }

    // 设置新的定时器，延迟300ms执行查询
    searchTimeout = setTimeout(() => {
        // 更新查询条件
        filters.contractTitle = inputFilters.contractTitle.trim()
        filters.partnerUnit = inputFilters.partnerUnit.trim()
        filters.handler = inputFilters.handler.trim()
        filters.signingStart = inputFilters.signingStart
        filters.signingEnd = inputFilters.signingEnd
        filters.status = inputFilters.status

        // 重置到第一页并刷新数据
        page.value = 1
        fetchList()
    }, 300)
}

function handleReset() {
    // 清空输入框
    inputFilters.contractTitle = ''
    inputFilters.partnerUnit = ''
    inputFilters.handler = ''
    inputFilters.signingStart = ''
    inputFilters.signingEnd = ''
    inputFilters.status = ''

    // 清空查询条件
    filters.contractTitle = ''
    filters.partnerUnit = ''
    filters.handler = ''
    filters.signingStart = ''
    filters.signingEnd = ''
    filters.status = ''

    // 重置到第一页并刷新数据
    page.value = 1
    fetchList()
}

function goto(p: number) {
    if (p < 1 || (totalPage.value && p > totalPage.value)) return
    page.value = p
    fetchList()
}

function jump() {
    if (!jumpPage.value) return
    const p = Math.max(1, Math.min(Number(jumpPage.value), Math.max(totalPage.value, 1)))
    goto(p)
}

const pagesToShow = computed(() => {
    const maxPage = Math.max(totalPage.value, 1)
    const current = Math.min(Math.max(page.value, 1), maxPage)
    const pages: { key: string; page: number; label: string; ellipsis?: boolean }[] = []
    const pushPage = (p: number) => pages.push({ key: `p-${p}`, page: p, label: String(p) })
    const pushEllipsis = (i: number) => pages.push({ key: `e-${i}`, page: -1, label: '...', ellipsis: true })

    if (maxPage <= 7) {
        for (let i = 1; i <= maxPage; i++) pushPage(i)
        return pages
    }
    pushPage(1)
    if (current > 4) pushEllipsis(1)
    const start = Math.max(2, current - 1)
    const end = Math.min(maxPage - 1, current + 1)
    for (let i = start; i <= end; i++) pushPage(i)
    if (current < maxPage - 3) pushEllipsis(2)
    pushPage(maxPage)
    return pages
})

// 从 URL 或 fileName 中提取文件名
function getFileName(url: string) {
    try {
        // 若是完整 URL，使用 pathname 的最后一段
        const u = new URL(url)
        const p = u.pathname || ''
        const segs = p.split('/')
        const last = segs[segs.length - 1] || url
        return decodeURIComponent(last)
    } catch {
        // 不是 URL，尝试直接返回字符串末段
        const segs = String(url).split(/[\\/]/)
        return segs[segs.length - 1] || String(url)
    }
}

function normalizeDateString(val: any) {
    if (!val) return ''
    try {
        const d = new Date(val)
        if (isNaN(d.getTime())) return ''
        return d.toISOString().slice(0, 10)
    } catch { return '' }
}


// 接入后端列表接口（固定为你提供的地址）
async function fetchList() {
    loading.value = true
    try {
        const params = new URLSearchParams()
        params.append('PageIndex', String(page.value))
        params.append('PageSize', String(pageSize.value))
        if (filters.contractTitle) { params.append('contractTitle', filters.contractTitle); params.append('ContractTitle', filters.contractTitle) }
        if (filters.partnerUnit) { params.append('partnerUnit', filters.partnerUnit); params.append('PartnerUnit', filters.partnerUnit); params.append('CarrierUnit', filters.partnerUnit); params.append('UnitName', filters.partnerUnit) }
        if (filters.handler) { params.append('handler', filters.handler); params.append('Handler', filters.handler) }
        if (filters.status) { params.append('status', filters.status); params.append('Status', filters.status) }
        if (filters.signingStart) { params.append('signingStart', filters.signingStart); params.append('SigningStart', filters.signingStart); params.append('startDate', filters.signingStart) }
        if (filters.signingEnd) { params.append('signingEnd', filters.signingEnd); params.append('SigningEnd', filters.signingEnd); params.append('endDate', filters.signingEnd) }
        params.append('t', String(Date.now()))

        const res = await read.get('contractmanagementread/api/ContractManagementControllers/GetCarriageContracts/Carriage', { params })
        const json: any = res?.data ?? {}
        const apiCode = Number(json?.code ?? json?.Code ?? (res?.status === 200 ? 200 : 500))
        const apiMessage = json?.message ?? json?.Message ?? ''
        if (apiCode !== 200 && apiMessage) {
            console.warn('查询返回非200:', apiCode, apiMessage)
        }
        const container: any = json?.data || {}
        total.value = Number(container?.TotalCount || 0)
        totalPage.value = Number(container?.TotalPage || 0)
        const list = Array.isArray(container?.data) ? container.data : []


        // 批量获取单位信息用于显示
        let unitMap = new Map()
        // 批量获取负责人（货主联系人）映射，用 ownerId -> name
        let ownerMap = new Map<number, string>()
        const needUnitInfo = list.some((it: any) => !it.PartnerUnit && !it.CarrierUnit && !it.UnitName && !it.unitName && !it.CompanyName && !it.companyName && (it.unitId || it.UnitId))

        if (needUnitInfo) {
            try {
                const res = await read.get('contractmanagementread/api/External/GetExternalList', { params: { PageIndex: 1, PageSize: 999 } })
                if (res?.status === 200) {
                    const data = res.data
                    const unitList = Array.isArray(data?.data) ? data.data : (Array.isArray(data?.data?.data) ? data.data.data : [])
                    unitList.forEach((unit: any) => {
                        const id = unit.Id || unit.id
                        const name = unit.UnitName ?? unit.unitName ?? unit.Name ?? unit.name ?? unit.CompanyName ?? unit.companyName
                        if (id && name) {
                            unitMap.set(id, name)
                        }
                    })
                }
            } catch (error) {
                // 静默处理错误
            }
        }

        // 批量获取线路信息用于显示（部分接口只返回线路ID）
        let routeMap = new Map<number, string>()
        const needOwnerInfo = list.some((it: any) => {
            const hasName = it.PartnerContact || it.PartnerContact || it.CarrierContact || it.CarrierContact || it.ownerName || it.OwnerName
            const hasId = it.OwnerId || it.ownerId || it.Owner || it.owner
            return !hasName && !!hasId
        })
        if (needOwnerInfo) {
            try {
                const res = await read.get('baseinforead/api/CargoOwner/GetCargoOwnerList', { params: { PageIndex: 1, PageSize: 999 } })
                if (res?.status === 200) {
                    const j: any = res.data ?? {}
                    const block = j?.data || j
                    const clist = Array.isArray(block) ? block : (Array.isArray(block?.data) ? block.data : [])
                    for (const c of clist) {
                        const id = Number(c.OwnerId ?? c.ownerId ?? c.Owner ?? c.owner ?? c.Id ?? c.id)
                        const name = c.ownerName ?? c.OwnerName ?? c.Contact ?? c.contact ?? c.Principal ?? c.principal ?? c.Name ?? c.name
                        if (Number.isFinite(id) && name) ownerMap.set(id, String(name))
                    }
                }
            } catch (e) {
                // ignore
            }
        }

        // 额外尝试：如果记录里有数值形式的负责人（或 OwnerId），但 ownerMap 没有对应姓名，逐条向后端按 id 查询姓名并缓存
        const ownerIdsToFetch = new Set<number>()
        for (const it of list) {
            // 候选字段可能为数字或数字字符串
            const candFields = [it.PartnerContact, it.CarrierContact, it.ownerName, it.OwnerName]
            for (const c of candFields) {
                if (c === null || c === undefined) continue
                const num = Number(c)
                if (!Number.isNaN(num) && Number.isFinite(num)) ownerIdsToFetch.add(num)
            }
            const idField = Number(it.OwnerId ?? it.ownerId ?? it.Owner ?? it.owner)
            if (!Number.isNaN(idField) && Number.isFinite(idField)) ownerIdsToFetch.add(idField)
        }
        const missingIds: number[] = []
        ownerIdsToFetch.forEach(id => { if (!ownerMap.has(id)) missingIds.push(id) })
        if (missingIds.length > 0) {
            try {
                await Promise.all(missingIds.map(async (id) => {
                    try {
                        const r = await read.get(`baseinforead/api/CargoOwner/GetCargoOwnerById/${encodeURIComponent(String(id))}`)
                        if (r?.status !== 200) return
                        const d = r.data?.data ?? r.data
                        if (d) {
                            const name = d.ownerName ?? d.OwnerName ?? d.Contact ?? d.contact ?? d.Principal ?? d.principal ?? d.Name ?? d.name
                            if (name) ownerMap.set(Number(id), String(name))
                        }
                    } catch (e) { /* ignore per-id errors */ }
                }))
            } catch (e) { /* ignore overall */ }
        }
        const needRouteInfo = list.some((it: any) => {
            return !it.Route && !it.route && !it.RouteName && !it.routeName && (it.RouteId || it.routeId || it.RouteInfoId || it.routeInfoId)
        })
        if (needRouteInfo) {
            try {
                const res = await read.get('contractmanagementread/api/ContractManagementControllers/Route', { params: { PageIndex: 1, PageSize: 999, t: Date.now() } })
                if (res?.status === 200) {
                    const j: any = res.data ?? {}
                    const block = j?.data || j
                    const rlist = Array.isArray(block?.data) ? block.data : (Array.isArray(block) ? block : [])
                    rlist.forEach((r: any) => {
                        const id = Number(r.Id ?? r.id ?? r.RouteId ?? r.routeId)
                        const start = r.Starting_point ?? r.starting_point ?? r.StartingPoint ?? r.startingPoint ?? r.From ?? r.from ?? ''
                        const dest = r.Destination ?? r.destination ?? r.EndPoint ?? r.endPoint ?? r.To ?? r.to ?? ''
                        const name = r.RouteName ?? r.routeName ?? r.Name ?? r.name ?? ''
                        let display = ''
                        if (start && dest) display = `${start}到${dest}`
                        else if (name) display = name
                        else display = String(id)
                        if (Number.isFinite(id) && display) routeMap.set(id, display)
                    })
                }
            } catch (e) {
                // ignore
            }
        }

        // 处理数据映射
        rows.value = list.map((it: any) => {
            let partnerUnit = it.PartnerUnit ?? it.CarrierUnit ?? it.UnitName ?? it.unitName ?? it.CompanyName ?? it.companyName

            // 如果外协单位信息缺失，从批量获取的映射中查找
            if (!partnerUnit && (it.unitId || it.UnitId)) {
                const unitId = it.unitId || it.UnitId
                partnerUnit = unitMap.get(unitId) || '-'
            }

            // 列表：按后端原样显示路由字段（若为对象则序列化为 JSON 字符串）
            const routeRaw = it.Route ?? it.route ?? it.RouteName ?? it.routeName ?? it.RouteId ?? it.routeId ?? it.RouteInfoId ?? it.routeInfoId ?? ''
            const finalRoute = (routeRaw === null || routeRaw === undefined) ? '' : (typeof routeRaw === 'object' ? JSON.stringify(routeRaw) : String(routeRaw))

            // 兼容多种后端路由字段命名：Route / route / RouteName / routeName / RouteId
            // 计算货主负责人显示：优先使用直接返回的字段（字符串名字），如果是数字或缺失则尝试从 ownerMap 映射 id->name
            const rawNames = [it.PartnerContact, it.CarrierContact, it.ownerName, it.OwnerName, it.PartnerContact, it.CarriageRepresentative, it.carriageRepresentative]
            let partnerContactDisplay = ''
            for (const cand of rawNames) {
                if (cand === null || cand === undefined) continue
                if (typeof cand === 'object') {
                    const name = cand.ownerName ?? cand.OwnerName ?? cand.Contact ?? cand.contact ?? cand.Name ?? cand.name
                    if (name && String(name).trim() !== '') { partnerContactDisplay = String(name); break }
                } else {
                    const s = String(cand).trim()
                    if (s === '') continue
                    // 如果不是纯数字，则直接显示
                    if (!/^\d+$/.test(s)) { partnerContactDisplay = s; break }
                    // 如果是数字，先尝试用 ownerMap 映射
                    const n = Number(s)
                    const mapped = ownerMap.get(n)
                    if (mapped) { partnerContactDisplay = mapped; break }
                }
            }
            // 若仍为空，尝试使用 OwnerId/ownerId 字段
            if (!partnerContactDisplay) {
                const ownerIdRaw = it.OwnerId ?? it.ownerId ?? it.Owner ?? it.owner
                const oid = Number(ownerIdRaw)
                if (!Number.isNaN(oid)) partnerContactDisplay = ownerMap.get(oid) || String(ownerIdRaw || '')
            }
            if (!partnerContactDisplay) partnerContactDisplay = '-'

            return {
                id: it.Id,
                contractNumber: it.ContractNumber,
                contractTitle: it.ContractTitle,
                partnerUnit: partnerUnit || '-',
                partnerContact: partnerContactDisplay,
                unitId: it.unitId || it.UnitId || '',
                carriageRepresentative: it.carriageRepresentative || it.CarriageRepresentative || '',
                route: finalRoute || '',
                // 兼容多种后端附件字段：fileUrl / filePath / contractAttachment
                attachments: Array.isArray(it.contractAttachments) ? it.contractAttachments : (it.contractAttachments ? String(it.contractAttachments).split(',') : (it.fileUrl ? [it.fileUrl] : (it.filePath ? [it.filePath] : []))),
                tonFreightRate: it.TonFreightRate,
                charterConditionTonnage: it.CharterConditionTonnage,
                charterAmount: it.CharterAmount,
                signingDate: normalizeDateString(it.SigningDate),
                handler: it.Handler,
                createdAt: normalizeDateString(it.CreatedAt),
                status: it.Status,
                approver: it.Approver
            }
        })
    } catch (e) {
        rows.value = []
        total.value = 0
        totalPage.value = 0
    } finally {
        loading.value = false
    }
}

onMounted(() => {
    const url = new URL(window.location.href)
    if (url.searchParams.get('refresh') === '1') {
        url.searchParams.delete('refresh')
        history.replaceState(null, '', `${url.pathname}${url.search}`)
    }
    fetchList()
})


</script>

<style scoped>
.page {
    padding: 16px;
}

.title {
    margin: 8px 0 12px;
    font-size: 18px;
}

.search {
    background: #f7f7f7;
    padding: 12px;
    border-radius: 6px;
    margin-bottom: 12px;
}

.row {
    display: flex;
    align-items: center;
    gap: 8px;
    margin-bottom: 8px;
    flex-wrap: wrap;
}

.row label {
    color: #333;
}

input,
select {
    height: 30px;
    padding: 0 8px;
    border: 1px solid #ddd;
    border-radius: 4px;
}

.btn {
    height: 30px;
    padding: 0 12px;
    border: 1px solid #ddd;
    background: #fff;
    border-radius: 4px;
    cursor: pointer;
}

.btn.primary {
    background: #1677ff;
    color: #fff;
    border-color: #1677ff;
}

.btn.danger {
    background: #ff4d4f;
    color: #fff;
    border-color: #ff4d4f;
}

.toolbar {
    display: flex;
    gap: 8px;
    margin: 8px 0;
}

.table {
    width: 100%;
    border-collapse: collapse;
    background: #fff;
}

.table th,
.table td {
    border: 1px solid #eee;
    padding: 8px;
    text-align: left;
}

.table thead {
    background: #fafafa;
}

.table a {
    color: #1677ff;
    text-decoration: none;
}

.table a.danger {
    color: #ff4d4f;
}

.table-wrapper {
    overflow: auto;
}

.pagination {
    display: flex;
    gap: 12px;
    align-items: center;
    justify-content: center;
    padding: 12px 0;
}

.pagination.advanced {
    gap: 6px;
}

.pagination .num {
    min-width: 32px;
    height: 28px;
    border: 1px solid #ddd;
    background: #fff;
    border-radius: 4px;
    cursor: pointer;
}

.pagination .num.active {
    background: #13c2c2;
    color: #fff;
    border-color: #13c2c2;
}

.pagination .num.ellipsis {
    cursor: default;
    padding: 0 8px;
}

.pagination .nav {
    min-width: 32px;
    height: 28px;
    border: 1px solid #ddd;
    background: #fff;
    border-radius: 4px;
    cursor: pointer;
}

.pagination .sum {
    color: #666;
    margin-right: 6px;
}

.pagination .jump {
    color: #666;
}

.pagination .jump-input {
    width: 56px;
    height: 28px;
    padding: 0 6px;
    border: 1px solid #ddd;
    border-radius: 4px;
}

.dialog-mask {
    position: fixed;
    inset: 0;
    background: rgba(0, 0, 0, 0.35);
    display: flex;
    align-items: center;
    justify-content: center;
}

.dialog {
    width: 520px;
    max-width: 90vw;
    background: #fff;
    border-radius: 8px;
    padding: 16px;
}

.dialog-footer {
    display: flex;
    justify-content: flex-end;
    margin-top: 12px;
}
</style>
